﻿using System;
using System.Threading;
using System.Threading.Tasks;
using ATS.Dto;
using ATSSDK.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using RestSharp;

namespace ATSSDK;

public class DefaultATSClient : IATSClient
{
    protected readonly ATSOptions Options;
    protected readonly ILogger Logger;
    protected readonly RestClient Client;

    public DefaultATSClient(IOptions<ATSOptions> optionAccessor, ILoggerFactory loggerFactory)
    {
        Options = optionAccessor.Value;
        Options.Validate();
        Logger = loggerFactory.CreateLogger("ATSClient");

        var restOtpions = new RestClientOptions()
        {
            BaseUrl = new Uri(Options.BaseUrl),
            Timeout = TimeSpan.FromSeconds(Options.Timeout),
            Authenticator = new CustomJwtAuthenticator(Options.ClientId, Options.ClientPassword),
        };
        restOtpions.Interceptors.Add(new ATSInterceptor(Logger));
        Options.RestClientOptionBuilder?.Invoke(restOtpions);
        Client = new RestClient(restOtpions);
    }

    #region Helpers

    protected virtual void EnsureSuccess(ApiResponse? response)
    {
        if (response is null)
        {
            throw new ATSException("Response is null.");
        }
        if (response.Code != 0)
        {
            throw new ATSException(response.ToJson());
        }
    }

    #endregion

    #region Product

    /// <inheritdoc/>
    public virtual async ValueTask<ProductItemDto?> GetProductByIdAsync(string id, CancellationToken cancellation = default)
    {
        var request = new RestRequest($"open/api/mes/product/{id}", Method.Get);
        var response = await Client.GetAsync<ApiResponse<ProductItemDto>>(request, cancellation);
        EnsureSuccess(response);
        return response?.Result;
    }

    /// <inheritdoc/>
    public virtual async ValueTask<ProductItemDto?> GetProductByCodeAsync(string code, CancellationToken cancellation = default)
    {
        var request = new RestRequest($"open/api/mes/product/material/{code}", Method.Get);
        var response = await Client.GetAsync<ApiResponse<ProductItemDto>>(request, cancellation);
        EnsureSuccess(response);
        return response?.Result;
    }

    /// <inheritdoc/>
    public async ValueTask<ProductItemDto> CreateProductAsync(ProductCreateInput input, CancellationToken cancellation = default)
    {
        var request = new RestRequest($"open/api/mes/product/create", Method.Post);
        request.AddJsonBody(input);
        var response = await Client.PostAsync<ApiResponse<ProductItemDto>>(request, cancellation);
        EnsureSuccess(response);
        return response!.Result!;
    }

    #endregion

    #region TestManufacturing

    /// <inheritdoc/>
    public async ValueTask<TestManufacturingItemDto> CreateManufacturingAsync(TestManufacturingCreateInput input, CancellationToken cancellation = default)
    {
        var request = new RestRequest($"open/api/mes/manufacturing/create", Method.Post);
        request.AddJsonBody(input);
        var response = await Client.PostAsync<ApiResponse<TestManufacturingItemDto>>(request, cancellation);
        EnsureSuccess(response);
        return response!.Result!;
    }

    /// <inheritdoc/>
    public async ValueTask ChangeManufacturingStatusAsync(TestManufacturingChangeStatusInput input, CancellationToken cancellation = default)
    {
        var request = new RestRequest($"open/api/mes/manufacturing/status", Method.Post);
        request.AddJsonBody(input);
        var response = await Client.PostAsync<ApiResponse>(request, cancellation);
        EnsureSuccess(response);
    }

    /// <inheritdoc/>
    public async ValueTask<TestManufacturingItemDto?> GetTestManufacturingByIdAsync(string id, CancellationToken cancellation = default)
    {
        var request = new RestRequest($"open/api/mes/manufacturing/{id}");
        var response = await Client.GetAsync<ApiResponse<TestManufacturingItemDto>>(request, cancellation);
        EnsureSuccess(response);
        return response?.Result;
    }

    /// <inheritdoc/>
    public async ValueTask<TestManufacturingItemDto?> GetTestManufacturingByCodeAsync(string code, CancellationToken cancellation = default)
    {
        var request = new RestRequest($"open/api/mes/manufacturing/code/{code}");
        var response = await Client.GetAsync<ApiResponse<TestManufacturingItemDto>>(request, cancellation);
        EnsureSuccess(response);
        return response?.Result;
    }

    #endregion
}
